package czh.cocoa.foundation;

import java.util.ArrayList;
import java.util.List;

import android.graphics.Paint;
import czh.cocoa.graphics.CGContext;
import czh.cocoa.graphics.CGFont;
import czh.cocoa.graphics.CGPoint;
import czh.cocoa.graphics.CGRect;
import czh.cocoa.graphics.CGSize;
import czh.cocoa.ui.UIFont;
import czh.cocoa.ui.UILineBreakMode;

import static czh.cocoa.ui.UIKit.*;
import static czh.cocoa.graphics.CGContext.*;

public class NSString extends NSObject {
	
	private String mStr;
	
	public NSString() {
		this("");
	}
	
	public NSString(NSString str) {
		this(str.toString());
	}
	
	public NSString(String str) {
		mStr = str;
	}
	
	public String toString() {
		return mStr;
	}

	public boolean isEqual(NSObject o) {
		if(o.isKindOfClass(NSString.class)) {
			NSString other = (NSString)o;
			return other.toString().equals(toString());
		}
		return false;
	}
	
	public int hash() {
		return toString().hashCode();
	}
	
	public int length() {
		return toString().length();
	}
	
	public NSArray componentsSeparatedByString(NSString separator) {
		String str = toString();
		NSMutableArray components = new NSMutableArray();
		String[] splits = str.split(separator.toString());
		for (String s : splits) {
			components.addObject(NSTR(s));
		}
		return components;
	}

	public NSRange rangeOfString(NSString str) {
		return rangeOfStringOptions(str, 0);
	}
	
	public NSRange rangeOfStringOptions(NSString str, int options) {
		return rangeOfStringOptionsRange(str, options, null);
	}
	
	public NSRange rangeOfStringOptionsRange(NSString str, int options, NSRange range) {
		NSString substr = range != null ? substringWithRange(range) : this;
		int index = substr.toString().indexOf(str.toString()); 
		if (index >= 0) { 
			return NSMakeRange(index + range.location + range.length, str.length());
		} else {
			return NSMakeRange(NSNotFound, 0);
		}
	}
	
	public NSString substringWithRange(NSRange range) {
		String str = toString().substring(range.location, range.location + range.length);
		return NSTR(str);
	}
	
	public NSString substringFromIndex(int index) {
		NSRange range = NSMakeRange(index, length() - index);
		return substringWithRange(range);
	}
	
	public NSString substringToIndex(int index) {
		NSRange range = NSMakeRange(0, index);
		return substringWithRange(range);
	}
	
	
//draw text
	
	public CGSize drawAtPointWithFont(CGPoint point, UIFont font) {
		return drawAtPointForWidthWithFontLineBreakMode(point, 9999, font, UILineBreakMode.WordWrap);
	}
	
	public CGSize drawAtPointForWidthWithFontLineBreakMode(CGPoint point, float width, 
			UIFont font, UILineBreakMode lineBreakMode) {
		CGContext ctx = UIGraphicsGetCurrentContext();
		CGContextSelectFont(ctx, font.fontName(), font.pointSize());
		Paint paint = CGContextGetPaint(ctx);
		CGRect rect = CGRectMake(point.x, point.y, width, paint.descent() - paint.ascent()); 
		return drawInRectWithFontLineBreakMode(ctx, paint, rect, lineBreakMode);
	}
	
	public CGSize drawInRectWithFont(CGRect rect, UIFont font) {
		return drawInRectWithFontLineBreakMode(rect, font, UILineBreakMode.WordWrap);
	}
	

	public CGSize drawInRectWithFontLineBreakMode(CGRect rect, UIFont font, UILineBreakMode lineBreakMode) {
		CGContext ctx = UIGraphicsGetCurrentContext();
		CGContextSelectFont(ctx, font.fontName(), font.pointSize());
		Paint paint = CGContextGetPaint(ctx);
		return drawInRectWithFontLineBreakMode(ctx, paint, rect, lineBreakMode);
	}
	
	private CGSize drawInRectWithFontLineBreakMode(CGContext ctx, Paint paint, 
							CGRect rect, UILineBreakMode lineBreakMode) {
	
		String text = toString();
		
		switch (lineBreakMode) {
			case WordWrap:
			case CharacterWrap:
			case Clip:
			case TailTruncation:
			{
				int cursor = 0;
				int text_len = text.length();
				int count = 0;
				float line_h = paint.descent() - paint.ascent();
				float text_h = line_h;
				float max_width = 0;
				float[] measured_width = new float[1];
				float line_width = 0;
				
				while(cursor < text_len && text_h <= rect.size.height) {
					count = paint.breakText(text, cursor, text_len, true, rect.size.width, measured_width);
					String sub_text;
					
					if(lineBreakMode == UILineBreakMode.TailTruncation && 
							text_h + line_h > rect.size.height &&
							cursor + count < text_len) {
						
						float dot_width = paint.measureText("...");
						line_width = dot_width + measured_width[0];
						int index = 0;
						while(line_width > rect.size.width) {
							int end = cursor + count - index;
							if(end >= cursor && end <= text_len) {
								index++;
								line_width = dot_width + paint.measureText(text, cursor, end);
							} else {
								index = -1;
								break;
							}
						}
						sub_text = (index != -1) ? text.substring(cursor, 
								cursor + count - index) + "..." : text.substring(cursor,cursor + 1);
						
					} else {
						
						line_width = measured_width[0];
						
						sub_text = text.substring(cursor, cursor + count);
						
					}
					
					CGContextShowTextAtPoint(ctx, rect.origin.x, rect.origin.y + text_h - line_h, sub_text);
					
					cursor += count;
					text_h += line_h;
					max_width = Math.max(max_width, line_width);
				}
					
				return CGSizeMake(max_width, text_h - line_h);
			}
		}
		return null;
		
	}
	
	public CGSize sizeWithFontConstrainedToSize(UIFont font, CGSize size) {
		return sizeWithFontConstrainedToSizeLineBreakMode(font, size, UILineBreakMode.WordWrap);
	}
	
	public CGSize sizeWithFontConstrainedToSizeLineBreakMode(UIFont font, CGSize size, 
			UILineBreakMode lineBreakMode) {
		Paint paint = new Paint();
		CGFont font0 = new CGFont(font.fontName());
		paint.setTypeface(font0.typeface());
		paint.setTextSize(font.pointSize());
		return sizeWithFontConstrainedToSizeLineBreakMode(paint, size, lineBreakMode); 
	}
	
	private CGSize sizeWithFontConstrainedToSizeLineBreakMode(Paint paint, CGSize size, 
			UILineBreakMode lineBreakMode) {
		
		String text = toString();
		
		switch (lineBreakMode) {
			case WordWrap:
			case CharacterWrap:
			case Clip:
			case TailTruncation:
			{
				int cursor = 0;
				int text_len = text.length();
				int count = 0;
				float line_h = paint.descent() - paint.ascent();
				float text_h = line_h;
				float max_width = 0;
				float[] measured_width = new float[1];
				float line_width = 0;
				
				while(cursor < text_len && text_h <= size.height) {
					count = paint.breakText(text, cursor, text_len, true, size.width, measured_width);
					
					if(lineBreakMode == UILineBreakMode.TailTruncation && 
							text_h + line_h >= size.height &&
							cursor + count < text_len) {
						
						float dot_width = paint.measureText("...");
						line_width = dot_width + measured_width[0];
						int index = 0;
						while(line_width > size.width) {
							int end = cursor + count - index;
							if(end >= cursor && end <= text_len) {
								index++;
								line_width = dot_width + paint.measureText(text, cursor, end);
							} else {
								//index = -1;
								line_width = measured_width[0];
								break;
							}
						}
						
					} else {
						
						line_width = measured_width[0];
						
					}
					
					cursor += count;
					text_h += line_h;
					max_width = Math.max(max_width, line_width);
				}
					
				return CGSizeMake(max_width, text_h - line_h); 
			}
		}
		
		return null;
	}
	
	public CGSize sizeWithFont(UIFont font) {
		return sizeWithFontForWidthLineBreakMode(font, 9999, UILineBreakMode.WordWrap); 
	}
	
	public CGSize sizeWithFontForWidthLineBreakMode(UIFont font, float width, UILineBreakMode lineBreakMode) {
		Paint paint = new Paint();
		CGFont font0 = new CGFont(font.fontName());
		paint.setTypeface(font0.typeface());
		paint.setTextSize(font.pointSize());
		CGSize size = CGSizeMake(width, paint.descent() - paint.ascent());
		return sizeWithFontConstrainedToSizeLineBreakMode(paint, size, lineBreakMode);	 
	}
	
	public CGSize sizeWithFontMinFontSizeActualFontSizeForWidthLineBreakMode(UIFont font, float minFontSize,
			float[] actualFontSize, float width,  UILineBreakMode lineBreakMode) {
		
		Paint paint = new Paint();
		CGFont font0 = new CGFont(font.fontName());
		paint.setTypeface(font0.typeface());
		
		String text = toString();
		
		int text_len = text.length();
		
		float[] measured_width = new float[1];
		
		float fontSize;
		
		CGSize size;
		
		float min_font_size = minFontSize > 0 ? minFontSize : font.pointSize();
		
		for (fontSize = font.pointSize(); fontSize >= min_font_size; fontSize--) {
			
			boolean done = false;
			
			paint.setTextSize(fontSize);
			
			switch (lineBreakMode) {
				case WordWrap:
				case CharacterWrap:
				case Clip:
				case TailTruncation:
				{					
					
					int count = paint.breakText(text, 0, text_len, true, width, measured_width);
					if (count >= text_len) {
						size = CGSizeMake(measured_width[0], paint.descent() - paint.ascent());
						done = true;
					}
					
				}
			}
			
			if(done) {
				break;
			}
			
		}
		
		if(fontSize < minFontSize) {
			fontSize = minFontSize;
		}
		
		if(lineBreakMode == UILineBreakMode.TailTruncation) {
			
			float dot_width = paint.measureText("...");
			float line_width = dot_width + measured_width[0];
			int index = 0;
			while(line_width > width) {
				if(text_len - index >= 0) {
					index++;
					line_width = dot_width + paint.measureText(text, 0, text_len - index);
				} else {
					index = -1;
					break;
				}
			}
			
			size = CGSizeMake(line_width, paint.descent() - paint.ascent());
			
		} else {
			
			size = CGSizeMake(measured_width[0], paint.descent() - paint.ascent());
			
		}
		
		if(actualFontSize != null) {
			actualFontSize[0] = fontSize; 
		}
		
		return size;

	}

}
